/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#include "resourcemanager.h"
#include <algorithm>
#include "mesh.h"
#include "cgmaterial.h"
#include "directx/dxtexture.h"
#include "functors.h"

#ifdef _DEBUG
#ifdef _MSC_VER
   #define new new( _CLIENT_BLOCK, __FILE__, __LINE__)
#endif
#endif // _DEBUG

namespace Engine
{
	using namespace std;
	/******************************************************************************************************/
	template<> ResourceManager* Singleton<ResourceManager>::m_singleton = 0;
	/******************************************************************************************************/
	ResourceManager::ResourceManager()
		:m_meshFactory(new MeshFactory)
		,m_materailFactory(new CGMaterialFactory)
		,m_textureFactory(new DXTextureFactory)
	{
		AddResourceFactory(m_meshFactory);
		AddResourceFactory(m_materailFactory);
		AddResourceFactory(m_textureFactory);
	}
	/******************************************************************************************************/
	ResourceManager::~ResourceManager()
	{
	}
	/******************************************************************************************************/
	ResourcePtr ResourceManager::Create(const std::string& filename, const std::string& type)
	{
		ResourcePtr resptr;
		ResourceMap::iterator res = m_resources.find(filename);
		if(res != m_resources.end())
		{
			resptr = res->second;
		}
		else
		{
			ResourceFactoryMap::iterator factory = m_factories.find(type);
			if(factory != m_factories.end())
			{
				RefPtr<Resource, WeakPtrExtension> pres (factory->second->CreateInstance(filename));
				m_resources.insert(ResourceMap::value_type(filename,pres));
				resptr = m_resources[filename];
			}
			else
				throw std::logic_error("Unknown resource type ResourceManager::Create");
		}
		Log::GetSingleton() << "Resource created : " << type << " " << filename << std::endl;
		return resptr;
	}
	/******************************************************************************************************/
	void ResourceManager::Remove(const std::string& filename)
	{
		Log::GetSingleton() << "Resource deleted : " << filename << std::endl;
		ResourceMap::iterator ires = m_resources.find(filename);
		if(ires != m_resources.end())
		{
			ires->second->UnLoad();
			m_resources.erase(ires);
		}
		else
			throw std::logic_error("Unknown resource. ResourceManager::Remove");
	}
	/******************************************************************************************************/
	void ResourceManager::TryRemove(const std::string& filename)
	{
		Log::GetSingleton() << "Try delete resource : " << filename << std::endl;
		ResourceMap::iterator ires = m_resources.find(filename);
		if(ires != m_resources.end())
		{
			if(!ires->second.IsReferenced())
			{
				Log::GetSingleton() << "Resource deleted : " << filename << std::endl;
				ires->second->UnLoad();
				m_resources.erase(ires);
			}
		}
		else
			throw std::logic_error("Unknown resource. ResourceManager::TryRemove");
	}
	/******************************************************************************************************/
	void ResourceManager::ReLoadAll()
	{
		for_each(m_resources.begin(), m_resources.end(),on2nd(m_fn(&Resource::ReLoad)));
	}
	/******************************************************************************************************/
	void ResourceManager::RemoveAll()
	{
		for_each(m_resources.begin(), m_resources.end(),on2nd(m_fn(&Resource::UnLoad)));
		m_resources.clear();
	}
	/******************************************************************************************************/
	void ResourceManager::AddResourceFactory(ResourceFactoryPtr factory)
	{
		m_factories.insert(ResourceFactoryMap::value_type(factory->GetType(),factory));
	}
	/******************************************************************************************************/
}
